#include "factory.h"

int exit_pipeFd[2];
int exit_flag=0;//父进程的退出标志
void exit_sigfunc(int signum)
{
    printf("要有序退出了\n");
    write(exit_pipeFd[1],"1",1);
    exit_flag=1;
}

int main(int argc,char* argv[])
{
    if(argc!=4)
    {
        printf("./thread_pool IP PORT THREAD_NUM\n");
        return -1;
    }

    //创建子进程，父进程负责有序退出，子进程往下走
    pipe(exit_pipeFd);
    while(fork())
    {
        signal(SIGUSR1,exit_sigfunc);
        wait(NULL);
        if(exit_flag)
        {
            exit(0);
        }
#ifdef DEBUG
        printf("子进程挂了，或走到异常分支啦，重启它\n");
#endif
    }

    //子进程走到下面去
    int threadNum=atoi(argv[3]);//线程数
#ifdef DEBUG
    printf("threadNum=%d\n",threadNum);
#endif
    factory_t f;//主数据结构，线程池工厂
    factoryInit(&f,threadNum); //工厂初始化
    factoryStart(&f);//启动线程
    int sock_fd,new_fd;
    
    tcp_init(argv[1],argv[2],&sock_fd);//网络初始化

    struct sockaddr_in clientAddr;
    socklen_t addrLen;

    taskQueue_t *pQue=&f.taskQueue;
    //注册监控sock_fd
    int epfd=epoll_create(1);
    epoll_add(epfd,sock_fd);

    //注册监控退出管道的读端
    epoll_add(epfd,exit_pipeFd[0]);

    int ready_fd_num,i,j,epoll_ctl_num=2;
    struct epoll_event evs[100];
    MYSQL *conn;//主线程的连接
    mysql_connect(&conn,0);//为数据库初始化连接
    while(1)
    {
        ready_fd_num=epoll_wait(epfd,evs,epoll_ctl_num,-1);
        for(i=0;i<ready_fd_num;i++)
        {
            if(evs[i].data.fd==sock_fd)
            {
                addrLen=sizeof(clientAddr);
                new_fd=accept(sock_fd,(struct sockaddr*)&clientAddr,&addrLen);
                ERROR_CHECK(new_fd,-1,"accept");
                //来了一个客户端，就epoll_add它
                epoll_add(epfd,new_fd);
                epoll_ctl_num+=1;
            }else if(evs[i].data.fd==exit_pipeFd[0])//要退出了
            {
                printf("线程池开始退出\n");
                pthread_mutex_lock(&pQue->mutex);
                f.exitFlag=1;//标记退出
                pthread_mutex_unlock(&pQue->mutex);
                for(j=0;j<threadNum;j++)
                {
                    pthread_cond_signal(&f.cond);//都唤醒
                }
                for(j=0;j<threadNum;j++)
                {
                    pthread_join(f.thidArr[j],NULL);
                }
                printf("线程池退出成功\n");
                exit(0);
            }else{
                int control_code;
                uint64_t login_flag;
                username_passwd_t user_passwd;
                int user_id;
                recv_protocal(evs[i].data.fd,&control_code,&user_passwd);
#ifdef DEBUG
                printf("%s %s\n",user_passwd.user_name,user_passwd.passwd);
#endif
                if(1==control_code)//注册
                {
                    //用户名已存在
                    if(check_username_exist(conn,user_passwd.user_name))
                    {
                        send_protocal(evs[i].data.fd,REGISTER_FAILED,NULL,0);
                    }else{
                        //把对应的用户名和密码放入数据库
                        login_flag=insert_new_user(conn,&user_passwd);
                        printf("注册成功\n");
                        //注册成功
                        send_protocal(evs[i].data.fd,REGISTER_SUCCESS,NULL,0);    
                    }
                }else if(2==control_code)//登录
                {
                    login_flag=check_login(conn,&user_passwd);
                    if(login_flag)
                    {
                        send_protocal(evs[i].data.fd,LOGIN_SUCCESS,NULL,0);//通知登录成功
                    }else{
                        send_protocal(evs[i].data.fd,LOGIN_FAILED,NULL,0);
                    }
                }
                if(login_flag)
                {
                    printf("主线程放任务到队列\n");
                    user_id=get_user_id(conn,user_passwd.user_name);
                    printf("%d\n",user_id);
                    //登录成功后才放入队列
                    taskEnQueue(pQue,evs[i].data.fd,user_id);
                    epoll_del(epfd,evs[i].data.fd);
                    epoll_ctl_num-=1;//监控的描述符数目减一
                    pthread_cond_signal(&f.cond);//唤醒一个子线程
                }
            }
        }

     
    }
    close(sock_fd);
    return 0;
}